
#include "controller_types.h"
#include <string.h>
#include "MCU.h"

#define USER_STROE_ADDR		0x0803F800

#define USER_INDEX_MAX		1

void user_store_read(uint32_t index, user_info_t* user){
	const uint8_t* p = (const uint8_t*)USER_STROE_ADDR + index * sizeof(*user);
	
	memcpy(user, p, sizeof(*user));
}

void user_store_write(uint32_t index, const user_info_t* user){
	const uint8_t* p = (const uint8_t*)user;	
    /* unlock the flash program/erase controller */
    fmc_unlock();

    /* clear all pending flags */
    fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR );
    /* erase the flash pages */
	fmc_page_erase(USER_STROE_ADDR);
	
    uint32_t address = USER_STROE_ADDR;
	uint32_t len = sizeof(*user);
	uint32_t data;
	
    /* program flash */
    while(len > 0){
		if(len > 4){
			memcpy(&data, p, sizeof(data));
			len -= 4;
		}
		else{
			data = 0xFFFFFFFF;
			memcpy(&data, p, len);
			len = 0;
		}
		fmc_word_program(address, data);
        fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR );
		address += 4;
		p += 4;
    }

    /* lock the main FMC after the erase operation */
    fmc_lock();
}

static uint8_t user_get_check_sum(const user_info_t* user){
	const uint8_t* p = (const uint8_t*)user;
	const uint8_t* pend = &user->check_sum;
	uint8_t check_sum = 0;

	while(p < pend){
		check_sum += *p;
		p++;
	}

	return ~ check_sum;
}

int user_table_init(void){
	return 0;
}

int user_table_read(uint32_t index, user_info_t* user){
	user_store_read(index, user);
	if(user_get_check_sum(user) != user->check_sum){
		return -1;
	}
	return 0;
}

int user_table_write(uint32_t index, user_info_t* user){
	user->flag |= 0x01;
	user->check_sum = user_get_check_sum(user);
	user_store_write(index, user);
	return 0;
}

int user_table_erase(uint32_t index){
	user_info_t u = {0};
	return user_table_write(0, &u);
}

int user_table_find(const void* token, int (*compare)(const void* tk, const user_info_t* u), user_info_t* user, uint32_t* index){
	uint32_t i;
	int ret;
	user_info_t u;
	
	for(i = 0; i < USER_INDEX_MAX; i++){
		ret = user_table_read(i, &u);
		if(ret){
			return ret;
		}
		if(compare(token, &u)){
			if(user){
				*user = u;
			}
			if(index){
				*index = i;
			}
			return 0;
		}
	}

	return -2;
}

int user_table_update_user(user_info_t* user){
	return user_table_write(0, user);
}

int user_table_remove_user_by_pin(user_pin_t pin){
	user_info_t u = {0};
	return user_table_write(0, &u);
}

int user_table_remove_user_by_token(const user_token_t* token){
	user_info_t u = {0};
	return user_table_write(0, &u);
}

int user_table_find_user_by_pin(user_pin_t pin, user_info_t* user){
	return user_table_read(0, user);
}

int user_table_find_user_by_token(const user_token_t* token, user_info_t* user){
	return user_table_read(0, user);
}



